package com.example.secondhandspringboot.controller;

import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.aigc.generation.models.QwenParam;
import com.alibaba.dashscope.aigc.multimodalconversation.*;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.exception.UploadFileException;
import com.alibaba.dashscope.utils.Constants;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.example.secondhandspringboot.constant.RedisConstant;
import com.example.secondhandspringboot.context.BaseContext;
import com.example.secondhandspringboot.domain.entity.Category;
import com.example.secondhandspringboot.domain.vo.AITalkVO;
import com.example.secondhandspringboot.domain.vo.AIvlVO;
import com.example.secondhandspringboot.properties.AIProperties;
import com.example.secondhandspringboot.results.Result;

import com.example.secondhandspringboot.template.QwenVlTemplate;
import com.google.gson.Gson;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

import java.util.*;

@RestController
@RequestMapping("/aiTalk")
@CrossOrigin
@Slf4j
@RequiredArgsConstructor
public class AIController {

    private final AIProperties aiProperties;
    private final RedisTemplate<String,Object> redisTemplate;
    private final QwenVlTemplate qwenVlTemplate;

    /**
     * 千问大语言模型
     * @return
     * @throws NoApiKeyException
     * @throws InputRequiredException
     */
    @GetMapping
    public Flux<ServerSentEvent<AITalkVO>> aiTalk() throws NoApiKeyException, InputRequiredException {
        //获取当前用户id
        Long userId = BaseContext.getCurrentId();
        String redisKey = RedisConstant.AI_CONTENT+userId;
        log.info("ai助手正在回答");
        Constants.apiKey=aiProperties.getApiKey();
        Generation gen = new Generation();

        List<Message> messages = new ArrayList<>();
        Message systemMsg = Message.builder().role(Role.SYSTEM.getValue()).content(aiProperties.getSystemContent()).build();
        messages.add(systemMsg);
        //从缓存中取出对话列表
        List<Map<String,String>> aiTalkVOList = (List<Map<String, String>>) redisTemplate.opsForList().index(redisKey,0);
        if (aiTalkVOList != null) {
            for (Map<String, String> map : aiTalkVOList) {
                String role = map.get("role");
                Message msg = null;
                if (Objects.equals(role,"assistant")){
                    msg = Message.builder().role(Role.ASSISTANT.getValue()).content(map.get("content")).build();
                }else if (Objects.equals(role,"user")){
                    msg = Message.builder().role(Role.USER.getValue()).content(map.get("content")).build();
                }
                messages.add(msg);
            }
        }

//        Message userMsg = Message.builder().role(Role.USER.getValue()).content("如何做西红柿炖牛腩？").build();
//        Message assistantMsg = Message.builder().role(Role.USER.getValue()).content("西红柿炖牛腩是一道美味的家常菜，下面是详细的步骤指导： ### 材料： - 牛腩 - 西红柿 - 姜 - 葱 - 八角、香叶、干辣椒（可选） - 冰糖 - 料酒 - 酱油 - 盐 - 香菜（装饰用，可选） - 油 - 水或高汤 ### 步骤： 1. **准备**： - 牛腩清洗干净，切成约3-4厘米见方的块。 - 西红柿烫皮：将西红柿用开水烫过，顶部划十字，剥去外皮，切成小块。 - 姜切片，葱切段，香菜切末（如果要用）。 2. **焯水**： - 牛腩放入冷水中，加入一些料酒，烧开后撇去浮沫，捞出冲洗干净，去除血水和杂质。 3. **炒香调料**： - 热锅凉油，放入葱姜、八角、香叶和干辣椒（如果有），炒出香味。 - 加入西红柿块，翻炒至出红色汁液，加入适量的糖（帮助提鲜，也可以根据口味调整）。 4. **炖煮**： - 将炒好的西红柿倒入锅中，与牛腩混合均匀。 - 如果使用电压力锅，可以将牛腩、调料和少许汤汁放入，选择炖煮模式；如果没有压力锅，就直接在炒锅中加入足够的水或高汤，没过牛腩。 - 开始炖煮，盖上锅盖，中小火慢炖，直到牛腩变得酥烂。 5. **调味**： - 炖至牛腩熟透，汤汁浓稠时，加入适量的盐调味。 - 如果喜欢，此时可以撒上香菜末增加颜色和香气。 6. **出锅**： - 关火，稍微静置让味道融合，然后盛盘即可。 记得根据个人口味调整火候、糖量和调料的使用，享受烹饪的过程和美食带来的满足感！").build();
//        Message userMsg1 = Message.builder().role(Role.USER.getValue()).content("可以不放香叶吗？").build();
//
//        messages.add(systemMsg);
//        messages.add(userMsg);
//        messages.add(assistantMsg);
//        messages.add(userMsg1);

        QwenParam param =
                QwenParam.builder().model("qwen-max-0428").messages(messages)
                        .resultFormat(QwenParam.ResultFormat.MESSAGE)
                        .topP(0.8).enableSearch(true)
                        .incrementalOutput(true)
                        .build();

        // 将Flowable转换为Flux以便于与WebFlux集成
        Flux<GenerationResult> generationFlux = Flux.from(gen.streamCall(param));

        StringBuilder stringBuilder = new StringBuilder();
        AITalkVO aiTalkVO = new AITalkVO();
        aiTalkVO.setRole("assistant");

        // 将每一条GenerationResult的内容映射为ServerSentEvent
        return generationFlux.map(result -> {
            String content = result.getOutput().getChoices().get(0).getMessage().getContent(); // 假设这是获取回复消息的方法
            stringBuilder.append(content);
            String data = Objects.equals(content, "") ? "[DONE]" : stringBuilder.toString();
            aiTalkVO.setContent(data);
            return ServerSentEvent.builder(aiTalkVO)
                    .id(String.valueOf(UUID.randomUUID()))
                    .data(aiTalkVO)
                    .build();
        });
    }

    /**
     * 千问视觉模型
     *
     * @return
     */
    @GetMapping("/qwenVL")
    public Result<AIvlVO> qwenVL(@RequestParam String imageURL){
        log.info("千问视觉模型服务启动");
        //将url的Http改成http
        imageURL = imageURL.substring(0,1).toLowerCase() + imageURL.substring(1);
        Constants.apiKey = aiProperties.getApiKey();
        MultiModalConversation conv = new MultiModalConversation();
        MultiModalMessageItemImage userImage = new MultiModalMessageItemImage(imageURL);
        MultiModalMessageItemText userText = new MultiModalMessageItemText(qwenVlTemplate.getHumanPrompt());
        MultiModalMessageItemText systemText = new MultiModalMessageItemText(qwenVlTemplate.getSystemPrompt());
        MultiModalConversationMessage systemMessage =
                MultiModalConversationMessage.builder().role(Role.SYSTEM.getValue())
                        .content(Collections.singletonList(systemText)).build();
        MultiModalConversationMessage userMessage =
                MultiModalConversationMessage.builder().role(Role.USER.getValue())
                        .content(Arrays.asList(userImage, userText)).build();
        MultiModalConversationParam param = MultiModalConversationParam.builder()
                .model("qwen-vl-max")
                .messages(Arrays.asList(systemMessage, userMessage))
                .topP(0.9)
                .build();

        AIvlVO aiVlVO = null;
        //最大循环次数
        int maxLoopNum = 2;
        while (true){
            if (maxLoopNum == 0){
                return Result.error("AI生成失败");
            }
            try {
                MultiModalConversationResult result = conv.call(param);
                System.out.println(result.getOutput().getChoices().get(0).getMessage().getContent().get(0).get("text").toString());
                aiVlVO = JSON.parseObject(result.getOutput().getChoices().get(0).getMessage().getContent().get(0).get("text").toString().replaceAll(" ",""), AIvlVO.class);
                aiVlVO.setDescription( aiVlVO.getDescription().replaceAll("\n\n", "\n").replaceAll(" ",""));
                break;
            } catch (Exception e) {
                log.info("图像识别发生错误:"+e);
                maxLoopNum -- ;
            }
        }
        return Result.success(aiVlVO);
    }



    /**
     * json字符串转对象
     * @param jsonString
     * @param clazz
     * @return
     * @param <T>
     */
    public <T> T jsonStrToObject(String jsonString, Class<T> clazz) {
        Gson gson = new Gson();
        return gson.fromJson(jsonString, clazz);
    }

    /**
     * 保存ai对话
     * @param aiTalkVOList
     * @return
     */
    @PostMapping
    public Result saveAiTalks(@RequestBody List<AITalkVO> aiTalkVOList){
        Long userId = BaseContext.getCurrentId();
        String redisKey = RedisConstant.AI_CONTENT+userId;
        log.info("缓存ai对话...");
        if (aiTalkVOList == null){
            return Result.error("对话列表为空");
        }
        //如果已存在则删除
        redisTemplate.delete(redisKey);
        redisTemplate.opsForList().leftPushAll(redisKey,aiTalkVOList);
        return Result.success();
    }

    /**
     * 删除ai对话
     * @return
     */
    @DeleteMapping
    public Result deleteAiTalk(){
        log.info("缓存删除");
        Long userId = BaseContext.getCurrentId();
        String redisKey = RedisConstant.AI_CONTENT+userId;
        //用户退出当前界面时删除缓存
        redisTemplate.delete(redisKey);
        return Result.success();
    }
}